package com.podium.generator.controller;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.podium.comment.AjaxResult;
import com.podium.generator.entity.GeneratorTable;
import com.podium.generator.service.GeneratorTableService;
import com.podium.generator.utils.VelocityInitializer;
import com.podium.generator.utils.VelocityUtil;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author 邵文泽
 * @description 代码生成数据库表控制器
 * @date 2025/4/16 11:02
 */
@Slf4j
@RestController
@RequestMapping("generator")
public class GeneratorController {


    @Autowired
    private GeneratorTableService generatorTableService;

    /**
     * 分页获取数据库表信息
     *
     * @param tableName 数据库表名
     */
    @GetMapping("databaseTables")
    public AjaxResult<IPage<GeneratorTable>> databaseTables(@RequestParam(defaultValue = "1") int pageNum,
                                                            @RequestParam(defaultValue = "10") int pageSize,
                                                            String tableName) {
        return new AjaxResult<IPage<GeneratorTable>>().success(generatorTableService.databaseTables(new Page<>(pageNum, pageSize), tableName));
    }

    /**
     * 导出数据库表并保存
     *
     * @param tableNames 数据库表名集合
     */
    @PostMapping("exportDatabaseTables")
    public AjaxResult<Void> exportDatabaseTables(@RequestBody List<String> tableNames) {
        if (tableNames == null || tableNames.isEmpty()) {
            return new AjaxResult<Void>().error("请选择要导入的数据库表！");
        }
        boolean row = generatorTableService.exportDatabaseTables(tableNames);
        return row ? new AjaxResult<Void>().success() : new AjaxResult<Void>().error("导入数据库表失败！");
    }

    /**
     * 分页获取数据库表信息
     *
     * @param tableName     数据库表名
     * @param tableDescribe 数据库表描述
     */
    @GetMapping("page")
    public AjaxResult<IPage<GeneratorTable>> getPage(@RequestParam(defaultValue = "1") int pageNum,
                                                     @RequestParam(defaultValue = "10") int pageSize,
                                                     String tableName,
                                                     String tableDescribe) {
        Page<GeneratorTable> page = new Page<>(pageNum, pageSize);
        return new AjaxResult<IPage<GeneratorTable>>().success(generatorTableService.page(page, tableName, tableDescribe));
    }

    /**
     * 根据ID获取数据库表信息
     */
    @GetMapping("{id}")
    public AjaxResult<GeneratorTable> getByInfo(@PathVariable Long id) {
        return new AjaxResult<GeneratorTable>().success(generatorTableService.getById(id));
    }

    /**
     * 添加数据库表信息
     *
     * @param generatorTable 数据库表信息
     */
    @PostMapping("/save")
    public AjaxResult<Void> save(@RequestBody GeneratorTable generatorTable) {
        boolean row = generatorTableService.save(generatorTable);
        return row ? new AjaxResult<Void>().success() : new AjaxResult<Void>().error();
    }

    /**
     * 更新数据库表信息
     *
     * @param generatorTable 数据库表信息
     */
    @PostMapping("/update")
    public AjaxResult<Void> update(@RequestBody GeneratorTable generatorTable) {
        boolean row = generatorTableService.updateById(generatorTable);
        return row ? new AjaxResult<Void>().success() : new AjaxResult<Void>().error();
    }

    /**
     * 删除数据库表信息
     *
     * @param ids 数据库表ID集合
     */
    @GetMapping("/remove/{ids}")
    public AjaxResult<Void> remove(@PathVariable Long[] ids) {
        if (ids == null || ids.length == 0) {
            return new AjaxResult<Void>().error("没有要删除的数据！");
        }
        for (Long id : ids) {
            generatorTableService.removeById(id);
        }
        return new AjaxResult<Void>().success();
    }


    /**
     * 代码生成
     *
     * @param ids 表ID集合
     * @return AjaxResult
     */
    @GetMapping("/previewGenerate/{ids}")
    public AjaxResult<JSONObject> codeGenerate(@PathVariable Long[] ids) {
        JSONObject generateMap = new JSONObject();
        for (Long id : ids) {
            GeneratorTable generatorTable = generatorTableService.getById(id);
            VelocityInitializer.initVelocity();
            VelocityContext velocityContext = VelocityUtil.initVelocityParams(generatorTable);
            JSONObject fileMap = new JSONObject();
            VelocityUtil.getVelocityList().forEach(template -> {
                StringWriter sw = new StringWriter();
                Template tpl = Velocity.getTemplate(template, "UTF-8");
                tpl.merge(velocityContext, sw);
                fileMap.put(VelocityUtil.getName(template, generatorTable), sw.toString());
            });
            generateMap.put(generatorTable.getClassName(), fileMap);
        }

        return new AjaxResult<JSONObject>().success(generateMap);
    }

    /**
     * 下载代码
     *
     * @param ids 表ID集合
     */
    @PostMapping("/downloadCode/{ids}")
    public void downloadCodeGenerate(@PathVariable Long[] ids, HttpServletResponse response) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(output);
        VelocityInitializer.initVelocity();
        // 循环生成文件
        for (Long id : ids){
            GeneratorTable generatorTable = generatorTableService.getById(id);
            VelocityContext velocityContext = VelocityUtil.initVelocityParams(generatorTable);
            for (String template : VelocityUtil.getVelocityList()) {
                StringWriter sw = new StringWriter();
                Template tpl = Velocity.getTemplate(template, "UTF-8");
                tpl.merge(velocityContext, sw);
                try {
                    zip.putNextEntry(new ZipEntry(VelocityUtil.getFileName(template, generatorTable)));
                    IOUtils.write(sw.toString(), zip, "UTF-8");
                    IOUtils.closeQuietly(sw);
                    zip.flush();
                    zip.closeEntry();
                } catch (IOException e) {
                    log.error("代码生成失败！", e);
                }
            }
        }
        IOUtils.closeQuietly(zip);
        response.reset();
        response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
        response.setHeader("Content-Disposition", "attachment; filename=\"podium.zip\"");
        response.addHeader("Content-Length", "" + output.toByteArray().length);
        response.setContentType("application/octet-stream; charset=UTF-8");
        IOUtils.write(output.toByteArray(), response.getOutputStream());
    }
}
